package cn.xm.user.service.impl;

import cn.xm.basic.constants.Constant;
import cn.xm.basic.dto.LogininfoDto;
import cn.xm.basic.dto.PhoneDto;
import cn.xm.basic.exception.BusinessException;
import cn.xm.basic.utils.MD5Utils;
import cn.xm.basic.utils.StrUtils;
import cn.xm.user.domain.Logininfo;
import cn.xm.user.domain.User;
import cn.xm.user.mapper.LogininfoMapper;
import cn.xm.user.mapper.UserMapper;
import cn.xm.user.service.UserService;
import cn.xm.basic.service.impl.BaseServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xm
 * @since 2022-12-22
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public void phoneRegister(PhoneDto phoneDto) {
        // 参数校验
        // 判断是否已注册
        Logininfo logininfo = logininfoMapper.findByPhone(phoneDto.getPhone());
        if (logininfo != null) {
            throw new BusinessException("该用户已注册");
        }
        // 校验验证码是否正确
        String smsCodeValue = (String)redisTemplate.opsForValue().get(phoneDto.getPhone() + ":" + Constant.REGISTER_NAME);
        // 如果没有表示短信已过期或没有获取到
        if (StringUtils.isEmpty(smsCodeValue)) {
            throw new BusinessException("短信验证码不存在或已过期");
        }
        // 有则判断验证码是否正确
        String onlyValue = smsCodeValue.split(":")[0];
        if (!onlyValue.equalsIgnoreCase(phoneDto.getCode())) {
            throw new BusinessException("短信验证码错误");
        }
        // 判断两次密码是否相同
        if (!phoneDto.getPassword().equals(phoneDto.getPasswordRepeat())) {
            throw new BusinessException("两次密码不一致");
        }
        // 初始化logininfo
        logininfo = new Logininfo();
        initLogininfo(phoneDto, logininfo);
        logininfoMapper.add(logininfo);
        // 添加user
        User user = new User();
        initUser(logininfo, user);
        userMapper.add(user);
    }

    @Override
    public Map<String, Object> login(LogininfoDto logininfoDto) {
        // 参数校验
        // 用username查是否存在该用户
        Logininfo logininfo = logininfoMapper.findByUsername(logininfoDto.getUsername(), logininfoDto.getType());
        if (logininfo == null) {
            throw new BusinessException("不存在该用户，请注册");
        }
        // 判断密码是否正确
        // 盐值加密后的密码
        String password = MD5Utils.encrypByMd5(logininfo.getSalt() + logininfoDto.getPassword());
        if (!logininfo.getPassword().equals(password)) {
            throw new BusinessException("密码错误");
        }
        // 登录成功后把登录信息存返回给前端
        logininfo.setType(null);
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        logininfo.setDisable(null);
        logininfo.setId(null);
        // 创建token
        String token = UUID.randomUUID().toString();
        // 将信息保存到redis
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        HashMap<String, Object> map = new HashMap<>();
        map.put("token",token);
        map.put("logininfo",logininfo);
        return map;
    }

    private void initUser(Logininfo logininfo, User user) {
        BeanUtils.copyProperties(logininfo, user);
        user.setCreatetime(new Date());
        user.setState(1);
        user.setLogininfoId(logininfo.getId());
    }

    private void initLogininfo(PhoneDto phoneDto, Logininfo logininfo) {
        logininfo.setUsername(phoneDto.getPhone());
        logininfo.setPhone(phoneDto.getPhone());
        String salt = StrUtils.getComplexRandomString(32);
        logininfo.setSalt(salt);
        logininfo.setDisable(true);
        String password = MD5Utils.encrypByMd5(salt + phoneDto.getPassword());
        logininfo.setPassword(password);
        logininfo.setType(1);
    }

}
